﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using HtmlAgilityPack;
using Mini.Model;
using Mini.Model.BaseModels;
using Mini.Resource;
using HtmlDocument = HtmlAgilityPack.HtmlDocument;

namespace Mini.Common
{
    public class FilterHelper
    {
        private static bool BlackList(string url)
        {
            var list = new List<string>
                {
                    Global.FontLink,
                    Global.addthis
                };
            return list.Select(item => url.IndexOf(item, StringComparison.Ordinal)).Any(index => index != -1);
        }
        public static List<HtmlNodeModel> FilterLinkInDocumentByTag(string urlFile)
        {
            var document = CreateDocument(urlFile);
            var tagList = Enum.GetValues(typeof(TagType));
            var listLink = new List<HtmlNodeModel>();
            foreach (var tag in tagList)
            {
                var tagName = tag.ToString().ToLower();
                var attributeNameOfTag = tag.GetCustomAttributeDescription();
                var listTags = document.DocumentNode.Descendants(tagName).ToList();
                foreach (var htmlNode in listTags)
                {
                    var link = htmlNode.GetAttributeValue(attributeNameOfTag, null);
                    if (string.IsNullOrWhiteSpace(link))
                        continue;

                    var htmlNodeModel = new HtmlNodeModel();

                    var tagType = (TagType)Enum.Parse(typeof(TagType), tag.ToString());
                    htmlNodeModel.TagType = tagType;

                    if (BlackList(link))
                        continue;

                    var icoFile = link.IndexOf(Global.Ico, StringComparison.Ordinal);
                    if (icoFile != -1)
                    {
                        htmlNodeModel.TagType = TagType.Img;
                    }

                    htmlNodeModel.Link = link;
                    listLink.Add(htmlNodeModel);
                }
            }

            var listTagsStyle = document.DocumentNode.Descendants("style").ToList();
            if (!listTagsStyle.Any()) return listLink;

            foreach (var htmlNode in listTagsStyle)
            {
                var content = htmlNode.InnerText;
                var cssUrllLink = RegexContent(content, RegexResource.UrlCss).ToList();
                if (!cssUrllLink.Any())
                    continue;

                foreach (var cssLink in cssUrllLink)
                {
                    var htmlNodeModel = new HtmlNodeModel
                    {
                        Link = cssLink,
                        TagType = TagType.Img
                    };
                    listLink.Add(htmlNodeModel);
                }
            }
            return listLink;
        }

        public static async Task<IEnumerable<string>> FilterLinkInFile(string urlFile, string regexLinkString)
        {
            var fileContent = await FileHepler.ReadTextAsync(urlFile);
            return RegexContent(fileContent, regexLinkString);
        }

        public static IEnumerable<string> RegexContent(string content, string regexString)
        {
            var regex = new Regex(content);
            var matchesCollection = regex.Matches(regexString);

            return from object item in matchesCollection select Regex.Replace(item.ToString(), RegexResource.RegexContent, "");
        }

        public static HtmlDocument CreateDocument(string urlFile)
        {
            return new HtmlWeb().Load(urlFile);
        }

        public static async Task<IEnumerable<ImageInCssModel>> FilterLinkInCssFiles(string pageLink, string folderItemPage, BindingList<AnalysisLinkModel> listLinkBindingSource, RichTextBox rtxtStatus)
        {
            var imageInCssList = new List<ImageInCssModel>();
            var fileType = string.Format(".{0}", ConvertHelper.ConvertFolderTypeToString(FolderType.Css));
            var fileList = FileHepler.GetAllFileFromFolder(folderItemPage, fileType);
            var regex = new Regex(RegexResource.UrlCss);
            var regexReplace = new Regex(RegexResource.RegexContent);
            foreach (var file in fileList)
            {
                var fileCurrent = listLinkBindingSource.FirstOrDefault(c => c.TagType == TagType.Link && c.LocalLink == file);
                if (fileCurrent == null)
                    continue;

                var messageCss = string.Format("filter file css {0} {1}", Environment.NewLine, file);

                await ProgramHelper.SetStatus(200, messageCss, rtxtStatus);

                
                var dataFile = await FileHepler.ReadTextAsync(file);
                var listUrl = regex.Matches(dataFile);

                var imageInCssModel = new ImageInCssModel
                {
                    CssData = dataFile,
                    CssLink = file
                };

                var rootOnlineLink = string.Empty;

                foreach (var urlItem in listUrl)
                {
                    var itemString = urlItem.ToString();

                    var messageImageInCss = string.Format("Get link online of Image{0}({1}) in css {2} {3}",
                       Environment.NewLine, itemString, Environment.NewLine, file);

                    await ProgramHelper.SetStatus(200, messageImageInCss, rtxtStatus);

                    if (string.IsNullOrEmpty(itemString)) continue;

                    itemString = itemString.Substring(4, itemString.Length - 4);
                    itemString = itemString.Substring(0, itemString.Length - 1);

                    var urlBeforeReplace = regexReplace.Replace(itemString, "");

                    itemString = UrlHelper.BestUrl(itemString);
                    urlBeforeReplace = UrlHelper.BestUrl(urlBeforeReplace);

                    if (string.IsNullOrEmpty(urlBeforeReplace)) continue;
                    var urlCss = new LinkBaseModel
                    {
                        BaseLink = itemString,
                    };

                    if (UrlHelper.IsUrl(urlBeforeReplace))
                    {
                        urlCss.OnlineLink = itemString;
                        imageInCssModel.ImageInCssLinks.Add(urlCss);
                    }
                    else
                    {
                        if (!string.IsNullOrEmpty(rootOnlineLink))
                        {
                            var linkOnline = string.Format("{0}/{1}", rootOnlineLink, urlBeforeReplace);
                            if (UrlHelper.IsUrlExits(linkOnline))
                            {
                                urlCss.OnlineLink = linkOnline;
                                imageInCssModel.ImageInCssLinks.Add(urlCss);
                                continue;
                            }
                        }

                        var pageLinkBeforeAnalysis = AnalysisUrl(pageLink);
                        var onlineLink = FindOnlineLinkOfLocalLink(pageLinkBeforeAnalysis, urlBeforeReplace);
                        if (onlineLink == null)
                            continue;

                        rootOnlineLink = onlineLink.RootOnlineLink;
                        urlCss.OnlineLink = onlineLink.OnlineLink;
                        imageInCssModel.ImageInCssLinks.Add(urlCss);
                    }

                }
                imageInCssList.Add(imageInCssModel);
            }
            return imageInCssList;
        }

        public static OnlineLinkOfLocalLinkModel FindOnlineLinkOfLocalLink(AnalysisUrlModel analysisUrl, string link)
        {
            if (string.IsNullOrWhiteSpace(link))
                return null;

            var websiteLink = analysisUrl.RootPage;

            var onlineLink = string.Format("{0}/{1}", websiteLink, link);

            if (UrlHelper.IsUrlExits(onlineLink))
                return new OnlineLinkOfLocalLinkModel
                {
                    OnlineLink = onlineLink,
                    RootOnlineLink = websiteLink
                };

            var rootPage = websiteLink;

            foreach (var segment in analysisUrl.Segments)
            {
                var indexOf = analysisUrl.Segments.IndexOf(segment);
                if (indexOf <= 0)
                    continue;

                rootPage = string.Format("{0}{1}", rootPage, segment);

                onlineLink = string.Format("{0}/{1}", rootPage, link);

                if (UrlHelper.IsUrlExits(onlineLink))
                    return new OnlineLinkOfLocalLinkModel
                    {
                        OnlineLink = onlineLink,
                        RootOnlineLink = rootPage
                    };
            }

            return null;
        }

        public static AnalysisUrlModel AnalysisUrl(string url)
        {
            var urlPage = new Uri(url);
            var segments = urlPage.Segments;
            var rootPage = string.Format("{0}://{1}{2}", urlPage.Scheme, urlPage.Authority, segments[0]);
            return new AnalysisUrlModel
            {
                RootPage = rootPage,
                Segments = segments,
            };
        }

        public static IEnumerable<AnalysisLinkModel> FindOnlineLink(string pageLink, List<HtmlNodeModel> links)
        {

            var onlineFullLink = links.Where(c => UrlHelper.IsUrl(c.Link)).ToList();
            var onlineLocalLink = links.Where(c => !UrlHelper.IsUrl(c.Link)).ToList();
            var listLink = new List<AnalysisLinkModel>();
            onlineFullLink.ForEach(htmlNodeModel =>
            {
                var link = UrlHelper.BestUrl(htmlNodeModel.Link);
                var isLinkExits = UrlHelper.IsUrlExits(link);

                var analysisLinkModel = new AnalysisLinkModel
                {
                    BaseLink = link,
                    OnlineLink = isLinkExits ? link : string.Empty,
                    TagType = htmlNodeModel.TagType
                };

                listLink.Add(analysisLinkModel);
            });
            if (!onlineLocalLink.Any()) return listLink;
            var pageLinkBeforeAnalysis = AnalysisUrl(pageLink);

            var rootOnlineLink = string.Empty;
            foreach (var htmlNodeModel in onlineLocalLink)
            {
                var link = UrlHelper.BestUrl(htmlNodeModel.Link);

                var analysisLinkModel = new AnalysisLinkModel();
                if (!string.IsNullOrEmpty(rootOnlineLink))
                {
                    var onlineLink = string.Format("{0}/{1}", rootOnlineLink, link);
                    if (UrlHelper.IsUrlExits(onlineLink))
                    {
                        analysisLinkModel.BaseLink = htmlNodeModel.Link;
                        analysisLinkModel.OnlineLink = onlineLink;
                        analysisLinkModel.TagType = htmlNodeModel.TagType;
                        listLink.Add(analysisLinkModel);
                        continue;
                    }
                }

                var onlineLinkResult = FindOnlineLinkOfLocalLink(pageLinkBeforeAnalysis, link);
                if (onlineLinkResult == null)
                    continue;

                rootOnlineLink = onlineLinkResult.RootOnlineLink;

                analysisLinkModel.BaseLink = htmlNodeModel.Link;
                analysisLinkModel.OnlineLink = onlineLinkResult.OnlineLink;
                analysisLinkModel.TagType = htmlNodeModel.TagType;

                listLink.Add(analysisLinkModel);
            }

            return listLink;
        }

        public static async Task<AnalysisLinkViewModel> AnalysisPage(PageModel pageModel, string projectDirectory)
        {
            // download page and get page detail before download page
            var pageDetail = await FileHepler.SavePage(pageModel.PageLink, pageModel.PageName, projectDirectory);
            // filter all link in page 
            var allLinkInPageByTag = FilterLinkInDocumentByTag(pageDetail.PageDirectory);
            // fileter all link css in line in page

            var allLink = FindOnlineLink(pageModel.PageLink, allLinkInPageByTag);

            return new AnalysisLinkViewModel
            {
                AnalysisLinkModels = allLink,
                PageModel = pageDetail
            };
        }
    }
}
